
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import * as zrUtil from 'zrender/lib/core/util.js';
import * as zrColor from 'zrender/lib/tool/color.js';
import { linearMap } from '../util/number.js';
import { warn } from '../util/log.js';
var each = zrUtil.each;
var isObject = zrUtil.isObject;
var CATEGORY_DEFAULT_VISUAL_INDEX = -1;

var VisualMapping =
/** @class */
function () {
	function VisualMapping(option) {
		var mappingMethod = option.mappingMethod;
		var visualType = option.type;
		var thisOption = this.option = zrUtil.clone(option);
		this.type = visualType;
		this.mappingMethod = mappingMethod;
		this._normalizeData = normalizers[mappingMethod];
		var visualHandler = VisualMapping.visualHandlers[visualType];
		this.applyVisual = visualHandler.applyVisual;
		this.getColorMapper = visualHandler.getColorMapper;
		this._normalizedToVisual = visualHandler._normalizedToVisual[mappingMethod];

		if (mappingMethod === 'piecewise') {
			normalizeVisualRange(thisOption);
			preprocessForPiecewise(thisOption);
		} else if (mappingMethod === 'category') {
			thisOption.categories ? preprocessForSpecifiedCategory(thisOption) // categories is ordinal when thisOption.categories not specified,
			// which need no more preprocess except normalize visual.
				: normalizeVisualRange(thisOption, true);
		} else {
			// mappingMethod === 'linear' or 'fixed'
			zrUtil.assert(mappingMethod !== 'linear' || thisOption.dataExtent);
			normalizeVisualRange(thisOption);
		}
	}

	VisualMapping.prototype.mapValueToVisual = function (value) {
		var normalized = this._normalizeData(value);

		return this._normalizedToVisual(normalized, value);
	};

	VisualMapping.prototype.getNormalizer = function () {
		return zrUtil.bind(this._normalizeData, this);
	};
	/**
   * List available visual types.
   *
   * @public
   * @return {Array.<string>}
   */

	VisualMapping.listVisualTypes = function () {
		return zrUtil.keys(VisualMapping.visualHandlers);
	}; // /**
	//  * @public
	//  */
	// static addVisualHandler(name, handler) {
	//     visualHandlers[name] = handler;
	// }

	/**
   * @public
   */

	VisualMapping.isValidType = function (visualType) {
		return VisualMapping.visualHandlers.hasOwnProperty(visualType);
	};
	/**
   * Convenient method.
   * Visual can be Object or Array or primary type.
   */

	VisualMapping.eachVisual = function (visual, callback, context) {
		if (zrUtil.isObject(visual)) {
			zrUtil.each(visual, callback, context);
		} else {
			callback.call(context, visual);
		}
	};

	VisualMapping.mapVisual = function (visual, callback, context) {
		var isPrimary;
		var newVisual = zrUtil.isArray(visual) ? [] : zrUtil.isObject(visual) ? {} : (isPrimary = true, null);
		VisualMapping.eachVisual(visual, function (v, key) {
			var newVal = callback.call(context, v, key);
			isPrimary ? newVisual = newVal : newVisual[key] = newVal;
		});
		return newVisual;
	};
	/**
   * Retrieve visual properties from given object.
   */

	VisualMapping.retrieveVisuals = function (obj) {
		var ret = {};
		var hasVisual;
		obj && each(VisualMapping.visualHandlers, function (h, visualType) {
			if (obj.hasOwnProperty(visualType)) {
				ret[visualType] = obj[visualType];
				hasVisual = true;
			}
		});
		return hasVisual ? ret : null;
	};
	/**
   * Give order to visual types, considering colorSaturation, colorAlpha depends on color.
   *
   * @public
   * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}
   *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']
   * @return {Array.<string>} Sorted visual types.
   */

	VisualMapping.prepareVisualTypes = function (visualTypes) {
		if (zrUtil.isArray(visualTypes)) {
			visualTypes = visualTypes.slice();
		} else if (isObject(visualTypes)) {
			var types_1 = [];
			each(visualTypes, function (item, type) {
				types_1.push(type);
			});
			visualTypes = types_1;
		} else {
			return [];
		}

		visualTypes.sort(function (type1, type2) {
			// color should be front of colorSaturation, colorAlpha, ...
			// symbol and symbolSize do not matter.
			return type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0 ? 1 : -1;
		});
		return visualTypes;
	};
	/**
   * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.
   * Other visuals are only depends on themself.
   */

	VisualMapping.dependsOn = function (visualType1, visualType2) {
		return visualType2 === 'color' ? !!(visualType1 && visualType1.indexOf(visualType2) === 0) : visualType1 === visualType2;
	};
	/**
   * @param value
   * @param pieceList [{value: ..., interval: [min, max]}, ...]
   *                         Always from small to big.
   * @param findClosestWhenOutside Default to be false
   * @return index
   */

	VisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {
		var possibleI;
		var abs = Infinity; // value has the higher priority.

		for (var i = 0, len = pieceList.length; i < len; i++) {
			var pieceValue = pieceList[i].value;

			if (pieceValue != null) {
				if (pieceValue === value // FIXME
        // It is supposed to compare value according to value type of dimension,
        // but currently value type can exactly be string or number.
        // Compromise for numeric-like string (like '12'), especially
        // in the case that visualMap.categories is ['22', '33'].
        || zrUtil.isString(pieceValue) && pieceValue === value + '') {
					return i;
				}

				findClosestWhenOutside && updatePossible(pieceValue, i);
			}
		}

		for (var i = 0, len = pieceList.length; i < len; i++) {
			var piece = pieceList[i];
			var interval = piece.interval;
			var close_1 = piece.close;

			if (interval) {
				if (interval[0] === -Infinity) {
					if (littleThan(close_1[1], value, interval[1])) {
						return i;
					}
				} else if (interval[1] === Infinity) {
					if (littleThan(close_1[0], interval[0], value)) {
						return i;
					}
				} else if (littleThan(close_1[0], interval[0], value) && littleThan(close_1[1], value, interval[1])) {
					return i;
				}

				findClosestWhenOutside && updatePossible(interval[0], i);
				findClosestWhenOutside && updatePossible(interval[1], i);
			}
		}

		if (findClosestWhenOutside) {
			return value === Infinity ? pieceList.length - 1 : value === -Infinity ? 0 : possibleI;
		}

		function updatePossible(val, index) {
			var newAbs = Math.abs(val - value);

			if (newAbs < abs) {
				abs = newAbs;
				possibleI = index;
			}
		}
	};

	VisualMapping.visualHandlers = {
		color: {
			applyVisual: makeApplyVisual('color'),
			getColorMapper: function () {
				var thisOption = this.option;
				return zrUtil.bind(thisOption.mappingMethod === 'category' ? function (value, isNormalized) {
					!isNormalized && (value = this._normalizeData(value));
					return doMapCategory.call(this, value);
				} : function (value, isNormalized, out) {
					// If output rgb array
					// which will be much faster and useful in pixel manipulation
					var returnRGBArray = !!out;
					!isNormalized && (value = this._normalizeData(value));
					out = zrColor.fastLerp(value, thisOption.parsedVisual, out);
					return returnRGBArray ? out : zrColor.stringify(out, 'rgba');
				}, this);
			},
			_normalizedToVisual: {
				linear: function (normalized) {
					return zrColor.stringify(zrColor.fastLerp(normalized, this.option.parsedVisual), 'rgba');
				},
				category: doMapCategory,
				piecewise: function (normalized, value) {
					var result = getSpecifiedVisual.call(this, value);

					if (result == null) {
						result = zrColor.stringify(zrColor.fastLerp(normalized, this.option.parsedVisual), 'rgba');
					}

					return result;
				},
				fixed: doMapFixed
			}
		},
		colorHue: makePartialColorVisualHandler(function (color, value) {
			return zrColor.modifyHSL(color, value);
		}),
		colorSaturation: makePartialColorVisualHandler(function (color, value) {
			return zrColor.modifyHSL(color, null, value);
		}),
		colorLightness: makePartialColorVisualHandler(function (color, value) {
			return zrColor.modifyHSL(color, null, null, value);
		}),
		colorAlpha: makePartialColorVisualHandler(function (color, value) {
			return zrColor.modifyAlpha(color, value);
		}),
		decal: {
			applyVisual: makeApplyVisual('decal'),
			_normalizedToVisual: {
				linear: null,
				category: doMapCategory,
				piecewise: null,
				fixed: null
			}
		},
		opacity: {
			applyVisual: makeApplyVisual('opacity'),
			_normalizedToVisual: createNormalizedToNumericVisual([0, 1])
		},
		liftZ: {
			applyVisual: makeApplyVisual('liftZ'),
			_normalizedToVisual: {
				linear: doMapFixed,
				category: doMapFixed,
				piecewise: doMapFixed,
				fixed: doMapFixed
			}
		},
		symbol: {
			applyVisual: function (value, getter, setter) {
				var symbolCfg = this.mapValueToVisual(value);
				setter('symbol', symbolCfg);
			},
			_normalizedToVisual: {
				linear: doMapToArray,
				category: doMapCategory,
				piecewise: function (normalized, value) {
					var result = getSpecifiedVisual.call(this, value);

					if (result == null) {
						result = doMapToArray.call(this, normalized);
					}

					return result;
				},
				fixed: doMapFixed
			}
		},
		symbolSize: {
			applyVisual: makeApplyVisual('symbolSize'),
			_normalizedToVisual: createNormalizedToNumericVisual([0, 1])
		}
	};
	return VisualMapping;
}();

function preprocessForPiecewise(thisOption) {
	var pieceList = thisOption.pieceList;
	thisOption.hasSpecialVisual = false;
	zrUtil.each(pieceList, function (piece, index) {
		piece.originIndex = index; // piece.visual is "result visual value" but not
		// a visual range, so it does not need to be normalized.

		if (piece.visual != null) {
			thisOption.hasSpecialVisual = true;
		}
	});
}

function preprocessForSpecifiedCategory(thisOption) {
	// Hash categories.
	var categories = thisOption.categories;
	var categoryMap = thisOption.categoryMap = {};
	var visual = thisOption.visual;
	each(categories, function (cate, index) {
		categoryMap[cate] = index;
	}); // Process visual map input.

	if (!zrUtil.isArray(visual)) {
		var visualArr_1 = [];

		if (zrUtil.isObject(visual)) {
			each(visual, function (v, cate) {
				var index = categoryMap[cate];
				visualArr_1[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;
			});
		} else {
			// Is primary type, represents default visual.
			visualArr_1[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;
		}

		visual = setVisualToOption(thisOption, visualArr_1);
	} // Remove categories that has no visual,
	// then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.

	for (var i = categories.length - 1; i >= 0; i--) {
		if (visual[i] == null) {
			delete categoryMap[categories[i]];
			categories.pop();
		}
	}
}

function normalizeVisualRange(thisOption, isCategory) {
	var visual = thisOption.visual;
	var visualArr = [];

	if (zrUtil.isObject(visual)) {
		each(visual, function (v) {
			visualArr.push(v);
		});
	} else if (visual != null) {
		visualArr.push(visual);
	}

	var doNotNeedPair = {
		color: 1,
		symbol: 1
	};

	if (!isCategory && visualArr.length === 1 && !doNotNeedPair.hasOwnProperty(thisOption.type)) {
		// Do not care visualArr.length === 0, which is illegal.
		visualArr[1] = visualArr[0];
	}

	setVisualToOption(thisOption, visualArr);
}

function makePartialColorVisualHandler(applyValue) {
	return {
		applyVisual: function (value, getter, setter) {
			// Only used in HSL
			var colorChannel = this.mapValueToVisual(value); // Must not be array value

			setter('color', applyValue(getter('color'), colorChannel));
		},
		_normalizedToVisual: createNormalizedToNumericVisual([0, 1])
	};
}

function doMapToArray(normalized) {
	var visual = this.option.visual;
	return visual[Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))] || {}; // TODO {}?
}

function makeApplyVisual(visualType) {
	return function (value, getter, setter) {
		setter(visualType, this.mapValueToVisual(value));
	};
}

function doMapCategory(normalized) {
	var visual = this.option.visual;
	return visual[this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX ? normalized % visual.length : normalized];
}

function doMapFixed() {
	// visual will be convert to array.
	return this.option.visual[0];
}
/**
 * Create mapped to numeric visual
 */

function createNormalizedToNumericVisual(sourceExtent) {
	return {
		linear: function (normalized) {
			return linearMap(normalized, sourceExtent, this.option.visual, true);
		},
		category: doMapCategory,
		piecewise: function (normalized, value) {
			var result = getSpecifiedVisual.call(this, value);

			if (result == null) {
				result = linearMap(normalized, sourceExtent, this.option.visual, true);
			}

			return result;
		},
		fixed: doMapFixed
	};
}

function getSpecifiedVisual(value) {
	var thisOption = this.option;
	var pieceList = thisOption.pieceList;

	if (thisOption.hasSpecialVisual) {
		var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);
		var piece = pieceList[pieceIndex];

		if (piece && piece.visual) {
			return piece.visual[this.type];
		}
	}
}

function setVisualToOption(thisOption, visualArr) {
	thisOption.visual = visualArr;

	if (thisOption.type === 'color') {
		thisOption.parsedVisual = zrUtil.map(visualArr, function (item) {
			var color = zrColor.parse(item);

			if (!color && process.env.NODE_ENV !== 'production') {
				warn('\'' + item + '\' is an illegal color, fallback to \'#000000\'', true);
			}

			return color || [0, 0, 0, 1];
		});
	}

	return visualArr;
}
/**
 * Normalizers by mapping methods.
 */

var normalizers = {
	linear: function (value) {
		return linearMap(value, this.option.dataExtent, [0, 1], true);
	},
	piecewise: function (value) {
		var pieceList = this.option.pieceList;
		var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);

		if (pieceIndex != null) {
			return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);
		}
	},
	category: function (value) {
		var index = this.option.categories ? this.option.categoryMap[value] : value; // ordinal value

		return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;
	},
	fixed: zrUtil.noop
};

function littleThan(close, a, b) {
	return close ? a <= b : a < b;
}

export default VisualMapping;